1 module hip.util.algorithm;
2 import std.traits:ReturnType;
3 
4 
5 ReturnType!(Range.front)[] array(Range)(Range range)
6 {
7     static if(__traits(hasMember, Range, "length"))
8     {
9         import hip.util.array;
10         size_t l = range.length;
11         typeof(return) ret = uninitializedArray!(typeof(return))(l);
12         foreach(i; 0..l)
13             ret[i] = range[i];
14     }
15     else
16     {
17         typeof(return) ret;
18         foreach(v; range)
19             ret~= v;
20     }
21     return ret;
22 }
23 
24 
25 /**
26 Copies the content of `source` into `target` and returns the
27 remaining (unfilled) part of `target`.
28 
29 Preconditions: `target` shall have enough room to accommodate
30 the entirety of `source`.
31 
32 Params:
33     source = an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
34     target = an output range
35 
36 Returns:
37     The unfilled part of target
38  */
39 T[] copyInto(T)(T[] source, T[] target)
40 {
41     assert(target.length >= source.length, "Cannot copy source range into a smaller target range.");
42 
43     bool overlaps = source.ptr < target.ptr + target.length && target.ptr < source.ptr + source.length;
44     if(overlaps)
45     {
46         if (source.ptr < target.ptr)
47             {
48                 foreach_reverse (idx; 0 .. source.length)
49                     target[idx] = source[idx];
50             }
51             else
52             {
53                 foreach (idx; 0 .. source.length)
54                     target[idx] = source[idx];
55             }
56             return target[source.length .. target.length];
57     }
58     else
59     {
60         target[0..source.length] = source[];
61         return target[source.length..$];
62     }
63 }
64 
65 auto map(Range, From, To)(Range range, scope To delegate (From data) func)
66 {
67     pragma(LDC_no_typeinfo)
68     struct Return
69     {
70         Range inputRange;
71         To delegate(From data) convert;
72         import hip.util.reflection :isArray;
73         static if(isArray!Range)
74         {
75             size_t counter = 0;
76             void popFront(){counter++;}
77             bool empty(){return counter == inputRange.length;}
78             To front(){return convert(inputRange[counter]);}
79         }
80         else
81         {
82             void popFront(){inputRange.popFront;}
83             bool empty(){return inputRange.empty;}
84             To front(){return convert(inputRange.front);}
85         }
86 
87         int opApply(scope int delegate(To) dg)
88         {
89             foreach(v; inputRange)
90             {
91                 int ret = dg(convert(v));
92                 if(ret) return ret;
93             }
94             return 0;
95         }
96         int opApply(scope int delegate(size_t, To) dg)
97         {
98             size_t i = 0;
99             foreach(v; inputRange)
100             {
101                 int ret = dg(i++, convert(v));
102                 if(ret) return ret;
103             }
104             return 0;
105         }
106     }
107     return Return(range, func);
108 }
109 
110 void put(Q, T)(Q range, T[] args ...) if(is(T == U*, U))
111 {
112     int i = 0;
113     foreach(v; range)
114     {
115         if(i >= args.length)
116             return;
117         *args[i] = v;
118         i++;
119     }
120 }
121 
122 void swap(T)(ref T a, ref T b)
123 {
124     T tempA = a;
125     a = b;
126     b = tempA;
127 }
128 
129 
130 int find(T)(in T[] array, scope bool function(T val) pred)
131 {
132     foreach(index, v; array)
133         if(pred(v))
134             return cast(int)index;
135     return -1;
136 }
137 
138 int findLast(T)(in T[] array, scope bool function(T val) pred)
139 {
140     foreach_reverse(index, v; array)
141         if(pred(v))
142             return cast(int)index;
143     return -1;
144 }
145 
146 
147 private static void swapElem(T)(ref T lhs, ref T rhs) @safe nothrow @nogc
148 {
149     T tmp = lhs;
150     lhs = rhs;
151     rhs = tmp;
152 }
153 
154 
155 T[] quicksort(T)(T[] array, scope bool delegate(T a, T b) @nogc nothrow @trusted comparison) nothrow @nogc @trusted
156 {
157     if (array.length < 2)
158         return array;
159 
160     static int partition(T* arr, int left, int right, typeof(comparison) comparison) nothrow @nogc @trusted
161     {
162         immutable int mid = left + (right - left) / 2;
163         T pivot = arr[mid];
164         // move the mid point value to the front.
165         swapElem(arr[mid],arr[left]);
166         int i = left + 1;
167         int j = right;
168         while (i <= j)
169         {
170             while(i <= j && comparison(arr[i], pivot) <= 0 )
171                 i++;
172 
173             while(i <= j && comparison(arr[j], pivot) > 0)
174                 j--;
175 
176             if (i < j)
177                 swapElem(arr[i], arr[j]);
178         }
179         swapElem(arr[i - 1], arr[left]);
180         return i - 1;
181     }
182 
183     void doQsort(T* array, int left, int right, typeof(comparison) comparison) nothrow @nogc @trusted
184     {
185         if (left >= right)
186             return;
187 
188         int part = partition(array, left, right, comparison);
189         doQsort(array, left, part - 1, comparison);
190         doQsort(array, part + 1, right, comparison);
191     }
192 
193     doQsort(array.ptr, 0, cast(int)(array.length) - 1, comparison);
194     return array;
195 }